package cn.stu.cms.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.stu.cms.dto.PageDto;
import cn.stu.cms.dto.RoleMenuDto;
import cn.stu.cms.mapper.RoleMenuMapper;
import cn.stu.cms.pojo.Menu;
import cn.stu.cms.pojo.RoleMenu;
import cn.stu.cms.pojo.Roles;
import cn.stu.cms.service.MenuService;
import cn.stu.cms.service.RoleMenuService;
import cn.stu.cms.service.RolesService;
import cn.stu.cms.util.BeanUtils;
import cn.stu.cms.util.CollUtils;
import cn.stu.cms.util.R;
import cn.stu.cms.vo.rolemenu.RightsVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.stu.cms.common.CacheConstants.ROUTER_CACHE;
import static cn.stu.cms.common.CommonConstants.*;


/**
 * 角色菜单服务实施
 *
 * @author gh
 * @date 2023/09/18
 */
@Service
@AllArgsConstructor
public class RoleMenuServiceImpl extends ServiceImpl<RoleMenuMapper, RoleMenu> implements RoleMenuService {

    private RolesService rolesService;

    private MenuService menuService;


    /**
     * 权限更新
     *
     * @param update 更新
     * @return {@link R}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ROUTER_CACHE, key = "'roleId:'+#update.roleId", beforeInvocation = true)
    public R<String> roleMenuUpdate(RoleMenuDto update) {
        if (update.getRoleId() == null) {
            return R.failed(ID_ERROR);
        }
        if (update.getRoleId() == ADMIN_ID) {
            int count = 0;
            for (Long menuId : update.getMenuIds()) {
                if (menuId == 20 || menuId == 23) {
                    count++;
                }
            }
            if (count < 2L) {
                return R.failed(DISALLOWED_OPERATION);
            }
        }
        Roles role = rolesService.getById(update.getRoleId());
        if (role == null) {
            return R.failed("角色" + NO_EXIST_MSG);
        }
        List<Long> newList = CollUtils.uniqueList(update.getMenuIds());
        //删除原有权限
        lambdaUpdate().eq(RoleMenu::getRoleId, update.getRoleId()).remove();
        //更新时间
        roleTimeUpdate(update.getRoleId());
        if (CollUtil.isEmpty(newList)) {
            return R.ok(EDIT_OK_MSG);
        }
        //查询所选菜单是否存在
        Long menuCount = menuService.lambdaQuery().in(Menu::getMenuId, newList).count();
        if (menuCount != newList.size()) {
            return R.failed(EDIT_FAIL_MSG);
        }
        List<RoleMenu> addList = newList.stream()
                .map(menuId -> new RoleMenu(role.getRoleId(), menuId, role.getRoleName()))
                .collect(Collectors.toList());
        saveBatch(addList, 100);
        return R.ok(EDIT_OK_MSG);
    }

    /**
     * 删除权限
     *
     * @param roleId 角色ID
     * @return {@link R}
     */
    @Override
    public R<String> roleMenuDel(Long roleId) {
        if (roleId == ADMIN_ID) {
            return R.failed(DISALLOWED_OPERATION);
        }
        boolean exists = lambdaQuery().eq(RoleMenu::getRoleId, roleId).exists();
        if (!exists) {
            return R.failed(ID_ERROR);
        }
        //更新时间
        roleTimeUpdate(roleId);
        lambdaUpdate().eq(RoleMenu::getRoleId, roleId).remove();
        return R.ok(DEL_OK_MSG);
    }


    /**
     * 角色菜单列表
     *
     * @param page     页面
     * @param roleName 角色名称
     * @return {@link R}
     */
    @Override
    public R<Page<RightsVo>> roleMenuList(PageDto<Roles> page, String roleName) {
        //查询角色
        rolesService.lambdaQuery().like(StrUtil.isNotBlank(roleName), Roles::getRoleName, roleName).page(page);
        List<Roles> list = page.getRecords();
        if (CollUtil.isEmpty(list)) {
            return R.ok(GET_INFO_OK);
        }
        //过滤角色id
        List<Long> roleList = list.stream().map(Roles::getRoleId).collect(Collectors.toList());
        //查询权限
        List<RoleMenu> roleMenus = lambdaQuery().in(RoleMenu::getRoleId, roleList).list();
        //根据角色id 对权限分组
        Map<Long, List<Long>> rmByRoleId = roleMenus.stream()
                .collect(Collectors.groupingBy(RoleMenu::getRoleId,
                        Collectors.mapping(RoleMenu::getMenuId, Collectors.toList())));
        //重组对象
        List<RightsVo> rightsVos = list.stream()
                .map(role -> {
                    RightsVo rightsVo = BeanUtils.copier(role, RightsVo.class);
                    rightsVo.setMenuIds(rmByRoleId.get(role.getRoleId()) != null ? rmByRoleId.get(role.getRoleId()) : new ArrayList<>());
                    return rightsVo;
                }).collect(Collectors.toList());
        Page<RightsVo> rightsVoPage = new Page<>();
        rightsVoPage.setRecords(rightsVos);
        rightsVoPage.setTotal(page.getTotal());
        return R.ok(rightsVoPage, GET_INFO_OK);
    }

    /**
     * 角色修改时间更新
     *
     * @param roleId 角色ID
     */
    public void roleTimeUpdate(Long roleId) {
        rolesService.lambdaUpdate().set(Roles::getUpdateTime, LocalDateTime.now()).eq(Roles::getRoleId, roleId);
    }
}
